{
 "nbformat": 4,
 "nbformat_minor": 0,
 "metadata": {
  "colab": {
   "provenance": []
  },
  "kernelspec": {
   "name": "python3",
   "display_name": "Python 3"
  },
  "language_info": {
   "name": "python"
  }
 },
 "cells": [
  {
   "cell_type": "code",
   "source": [
    "# Copyright 2023 The Cirq Developers\n",
    "#\n",
    "# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
    "# you may not use this file except in compliance with the License.\n",
    "# You may obtain a copy of the License at\n",
    "#\n",
    "#     https://www.apache.org/licenses/LICENSE-2.0\n",
    "#\n",
    "# Unless required by applicable law or agreed to in writing, software\n",
    "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
    "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
    "# See the License for the specific language governing permissions and\n",
    "# limitations under the License."
   ],
   "metadata": {
    "id": "NNegRqB9GoU_"
   },
   "execution_count": 1,
   "outputs": []
  },
  {
   "cell_type": "markdown",
   "source": [
    "# Quantum utility\n",
    "\n",
    "This colab contains code for simulating a circuit described in [1] on a subset\n",
    "of qubits sufficient for reproducing the results in Fig. 4b. Running this simulation requires ~6GB of RAM, which may require a local runtime.\n",
    "Additional RAM and/or compute cores can improve performance.\n",
    "\n",
    "[1] Kim, Y., Eddins, A., Anand, S. et al. Evidence for the utility of quantum\n",
    "computing before fault tolerance. Nature 618, 500–505 (2023).\n",
    "https://doi.org/10.1038/s41586-023-06096-3"
   ],
   "metadata": {
    "id": "_7E8VdZOYL-V"
   }
  },
  {
   "cell_type": "code",
   "source": [
    "try:\n",
    "    import cirq\n",
    "except ImportError:\n",
    "    print(\"installing cirq...\")\n",
    "    !pip install --quiet cirq\n",
    "    print(\"installed cirq.\")\n",
    "\n",
    "try:\n",
    "    import qsimcirq\n",
    "except ImportError:\n",
    "    print(\"installing qsimcirq...\")\n",
    "    !pip install --quiet qsimcirq\n",
    "    print(\"installed qsimcirq.\")"
   ],
   "metadata": {
    "id": "X8KW5a0cnRhr"
   },
   "execution_count": 2,
   "outputs": []
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "id": "82JvqINQiEpy"
   },
   "outputs": [],
   "source": [
    "import cirq\n",
    "import qsimcirq\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "import sympy"
   ]
  },
  {
   "cell_type": "code",
   "source": [
    "# These 28 qubits construct the three \"bricks\" around qubit 62:\n",
    "#\n",
    "#           41-42-43-44-45\n",
    "#           |           |\n",
    "#           53          54\n",
    "#           |           |\n",
    "#     58-59-60-61-62-63-64-65-66\n",
    "#     |           |           |\n",
    "#     71          72          73\n",
    "#     |           |           |\n",
    "#     77-78-79-80-81-82-83-84-85\n",
    "#\n",
    "qubit_ids = [\n",
    "    *range(41, 46),  # row 0\n",
    "    *range(53, 55),  # row 1\n",
    "    *range(58, 67),  # row 2\n",
    "    *range(71, 74),  # row 3\n",
    "    *range(77, 86),  # row 4\n",
    "]\n",
    "q = {i: cirq.NamedQubit(f'q{i}') for i in qubit_ids}\n",
    "qubits = list(q.values())\n",
    "\n",
    "# This parameter will be used to sweep over X rotation angles.\n",
    "theta = sympy.Symbol('theta')\n",
    "x_rotations = cirq.Moment(cirq.rx(theta).on_each(qubits))\n",
    "\n",
    "# This is the ZZ(-pi/2) gate described in equation (2).\n",
    "zz_pi_2 = cirq.ZZ**-0.5\n",
    "\n",
    "# Each of these moments performs ZZ interactions along\n",
    "# 1/3 of the edges in the region, corresponding to the\n",
    "# red, blue, and green edges in Fig. 1b.\n",
    "zz_layer_1 = cirq.Moment(\n",
    "    zz_pi_2(q[41], q[53]),\n",
    "    zz_pi_2(q[43], q[44]),\n",
    "    zz_pi_2(q[58], q[71]),\n",
    "    zz_pi_2(q[59], q[60]),\n",
    "    zz_pi_2(q[61], q[62]),\n",
    "    zz_pi_2(q[63], q[64]),\n",
    "    zz_pi_2(q[72], q[81]),\n",
    "    zz_pi_2(q[73], q[85]),\n",
    "    zz_pi_2(q[78], q[79]),\n",
    "    zz_pi_2(q[83], q[84]),\n",
    ")\n",
    "zz_layer_2 = cirq.Moment(\n",
    "    zz_pi_2(q[42], q[43]),\n",
    "    zz_pi_2(q[44], q[45]),\n",
    "    zz_pi_2(q[53], q[60]),\n",
    "    zz_pi_2(q[54], q[64]),\n",
    "    zz_pi_2(q[62], q[63]),\n",
    "    zz_pi_2(q[65], q[66]),\n",
    "    zz_pi_2(q[71], q[77]),\n",
    "    zz_pi_2(q[79], q[80]),\n",
    "    zz_pi_2(q[81], q[82]),\n",
    "    zz_pi_2(q[84], q[85]),\n",
    ")\n",
    "zz_layer_3 = cirq.Moment(\n",
    "    zz_pi_2(q[41], q[42]),\n",
    "    zz_pi_2(q[45], q[54]),\n",
    "    zz_pi_2(q[58], q[59]),\n",
    "    zz_pi_2(q[60], q[61]),\n",
    "    zz_pi_2(q[62], q[72]),\n",
    "    zz_pi_2(q[64], q[65]),\n",
    "    zz_pi_2(q[66], q[73]),\n",
    "    zz_pi_2(q[77], q[78]),\n",
    "    zz_pi_2(q[80], q[81]),\n",
    "    zz_pi_2(q[82], q[83]),\n",
    ")\n",
    "\n",
    "# This circuit encapsulates a single \"step\", as shown\n",
    "# in Fig. 1a.\n",
    "step = cirq.FrozenCircuit(x_rotations, zz_layer_1, zz_layer_2, zz_layer_3)\n",
    "# Uncomment this line to print the circuit diagram for\n",
    "# a single step of the circuit.\n",
    "# print(step)"
   ],
   "metadata": {
    "id": "k6D7DylOnQw1"
   },
   "execution_count": 4,
   "outputs": []
  },
  {
   "cell_type": "code",
   "source": [
    "# The circuit used to generate Fig. 4b consists of 20 steps.\n",
    "# Changing \"repetitions\" here will adjust the number of steps simulated.\n",
    "all_steps = cirq.CircuitOperation(step, repetitions=20)\n",
    "circuit = cirq.Circuit(all_steps)\n",
    "\n",
    "# This is the Z observable on qubit 62.\n",
    "observables = [cirq.Z(q[62])]\n",
    "\n",
    "# These are approximately the values of theta plotted for experimental values\n",
    "# in Fig. 4b. Changing this list will adjust the simulation to test other\n",
    "# theta values.\n",
    "theta_values = [*np.linspace(0, 0.8, 9), 1, np.pi / 2]\n",
    "params = cirq.Points(key=\"theta\", points=theta_values)\n",
    "\n",
    "# These options are used to tune qsim performance.\n",
    "# On CPU, \"cpu_threads\" should be set to the number of cores available.\n",
    "opt = qsimcirq.QSimOptions(max_fused_gate_size=4, cpu_threads=24)\n",
    "# To use GPU instead, uncomment this line:\n",
    "# opt = qsimcirq.QSimOptions(use_gpu=True, gpu_mode=1)\n",
    "simulator = qsimcirq.QSimSimulator(qsim_options=opt)"
   ],
   "metadata": {
    "id": "ZtqG4RpBK1IY"
   },
   "execution_count": 5,
   "outputs": []
  },
  {
   "cell_type": "code",
   "source": [
    "%%time\n",
    "# This will log after each value of theta is simulated. Its purpose is to\n",
    "# give an indication of total runtime before all simulations finish.\n",
    "results = []\n",
    "for i, result in enumerate(\n",
    "    simulator.simulate_expectation_values_sweep_iter(circuit, observables, params)\n",
    "):\n",
    "    results.append(result)\n",
    "    print(f\"Completed theta={theta_values[i]:.3f}; value={result}\")\n",
    "\n",
    "# Runtimes logged in the output of this cell were achieved using a machine with\n",
    "# 24 cores and 80GB of RAM."
   ],
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "Sw0bgSywunbR",
    "outputId": "084ecb1c-6204-43c5-c3d7-fd68c1535814"
   },
   "execution_count": 6,
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": [
      "Completed theta=0.000; value=[(1+0j)]\n",
      "Completed theta=0.100; value=[(0.9957248494988796-1.0945159604072678e-09j)]\n",
      "Completed theta=0.200; value=[(0.9785691808859784+5.244455029047104e-09j)]\n",
      "Completed theta=0.300; value=[(0.9227771228638144+1.0042918680018413e-08j)]\n",
      "Completed theta=0.400; value=[(0.8549387301071374-1.899016572015007e-10j)]\n",
      "Completed theta=0.500; value=[(0.7790027681081058-6.695167987532044e-09j)]\n",
      "Completed theta=0.600; value=[(0.6093954499261214-4.028657081304886e-09j)]\n",
      "Completed theta=0.700; value=[(0.4257824480390532-1.4948143005177584e-10j)]\n",
      "Completed theta=0.800; value=[(0.20900853480698267-9.495178461289215e-11j)]\n",
      "Completed theta=1.000; value=[(0.011624567839324501+1.1215127671718956e-12j)]\n",
      "Completed theta=1.571; value=[(-4.8872551798147e-09-6.909408682133451e-16j)]\n",
      "CPU times: user 1h 25min 36s, sys: 38 s, total: 1h 26min 14s\n",
      "Wall time: 3min 55s\n"
     ]
    }
   ]
  },
  {
   "cell_type": "code",
   "source": [
    "# Each element of \"results\" is a list of one expectation value (for Z[62]).\n",
    "plot_results = [x[0].real for x in results]\n",
    "\n",
    "# Plot the results in the format of Fig. 4b.\n",
    "plt.plot(np.array(theta_values), plot_results, 'bo')\n",
    "plt.xlabel(r\"$ R_X $ angle $ \\theta_h $\")\n",
    "plt.ylabel(r\"$ \\langle Z_{62} \\rangle $\")\n",
    "plt.xticks(np.linspace(0, np.pi / 2, 5), [\"0\", \"π/8\", \"π/4\", \"3π/8\", \"π/2\"])\n",
    "plt.yticks(np.linspace(0, 1, 6))\n",
    "plt.show()"
   ],
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 283
    },
    "id": "uCpJDwfwcaTg",
    "outputId": "c958f2f0-83ac-4ee4-a92a-0c0e520d5a26"
   },
   "execution_count": 7,
   "outputs": [
    {
     "output_type": "display_data",
     "data": {
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ],
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYUAAAEKCAYAAAD9xUlFAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/P9b71AAAACXBIWXMAAAsTAAALEwEAmpwYAAAVjUlEQVR4nO3dfZBdd33f8fdHNoZsAAORaFPrYd3gFFQeHLK4MKStg3mQSWKXAVK7S0KAsjSpQ4eHJKYiDiGjSQnTMAZckoUwPHTBcRICojgYmsIwSWtqGYzBduyqtiTbkCKIoXE3YIS//eOcPb5a62FX2j337t73a0Zzz/nd3733q6NdffZ3ztnfL1WFJEkAG4ZdgCRpdBgKkqSOoSBJ6hgKkqSOoSBJ6pw67AJO1saNG2tycnLYZUjSmnL99dd/o6o2LW5f86EwOTnJnj17hl2GJK0pSfYfqd3TR5KkjqEgSeoYCpKkjqEgSeoYCpKkTm+hkOS9Sb6e5CtHeT5J3p5kb5Ibkzx1tWqZm4PJSdiwoXmcm1utT5KktaXPkcL7gB3HeP584Kz2zwzwrtUoYm4OZmZg/36oah5nZk48GAwYSetJb6FQVZ8D/uYYXS4EPlCNa4FHJfnhla5j506Ynz+8bX6+aV+ulQ4YSRq2UbqmcAZw58D+XW3bgySZSbInyZ6DBw8u60MOHFhe+7GsZMBI0igYpVBYsqqaraqpqpratOlBv6V9TFu3Lq/9WFYyYBZ4OkrSMI1SKNwNbBnY39y2rahdu2Bi4vC2iYmmfblWMmDA01GShm+UQmE38PPtXUhPB75dVV9b6Q+ZnobZWdi2DZLmcXa2aV+ulQwY8HSUpOFLX2s0J/kwcC6wEfg/wG8ADwGoqt9LEuCdNHcozQMvq6rjznQ3NTVVw5wQb26u+U/7wIFmhLBr14kFDDSnjI70z5HA/fefXJ2SNCjJ9VU19aD2vkJhtQw7FFbS5GRzymixbdtg376+q5G0nh0tFEbp9NHYW+nTUZK0XIbCCFnJ6x2SdCLW/CI76830tCEgaXgcKUiSOoaCJKljKEiSOoaCJKljKKxjzqMkabm8+2idWphHaWHajIV5lMC7myQdnSOFdcp5lCSdCENhnVqNab0lrX+Gwjq10tN6SxoPhsI65TxKkk6EobBOOY+SpBPh3UfrmPMoSVouRwqSpI6hIEnqGAqSpI6hIEnqGAqSpI6hoCVzgj1p/fOWVC2JE+xJ48GRgpbECfak8WAoaEmcYE8aD4aClsQJ9qTxYChoSZxgTxoPhoKWxAn2pPHg3UdaMifYk9Y/RwqSpI6hIEnqGAqSpE6voZBkR5Jbk+xNcukRnt+a5DNJvpjkxiTP77M+SRp3vYVCklOAK4Dzge3AxUm2L+r2RuCqqvox4CLgP/VVnySp35HCOcDeqrq9qu4DrgQuXNSngEe226cDX+2xPkkae32GwhnAnQP7d7Vtg94EvCTJXcDVwC8f6Y2SzCTZk2TPwYMHV6NWSRpLo3ah+WLgfVW1GXg+8MEkD6qxqmaraqqqpjZt2tR7kTp5TsMtjaY+f3ntbmDLwP7mtm3QK4AdAFX1P5I8DNgIfL2XCtULp+GWRlefI4XrgLOSnJnkNJoLybsX9TkAnAeQ5AnAwwDPD60zTsMtja7eQqGqDgGXANcAt9DcZXRTkjcnuaDt9jrglUm+BHwY+IWqqr5qVD+chlsaXb3OfVRVV9NcQB5su2xg+2bgmX3WpP5t3dqcMjpSu6ThGrULzRoDTsMtjS5DQb1zGm5pdDl1tobCabil0eRIQZLUMRQkSR1DQZLUMRQkSR1DQZLUMRQkSR1DQZLUMRQkSR1DQZLUMRQkSR1DQZLUMRQkSR1DQZLUMRQkSR1DQZLUMRQkSR1DQZLUMRQkSR1DQZLUMRQkSR1DQZLUMRQkSR1DQZLUMRQkSR1DQZLUMRS05s3NweQkbNjQPM7NDbsiae06ddgFSCdjbg5mZmB+vtnfv7/ZB5ieHl5d0lrV60ghyY4ktybZm+TSo/T52SQ3J7kpyYf6rE9rz86dDwTCgvn5pl3S8vU2UkhyCnAF8BzgLuC6JLur6uaBPmcBbwCeWVX3JHlsX/VpbTpwYHntko6tz5HCOcDeqrq9qu4DrgQuXNTnlcAVVXUPQFV9vcf6tAZt3bq8dknH1mconAHcObB/V9s26EeBH03yl0muTbLjSG+UZCbJniR7Dh48uErlai3YtQsmJg5vm5ho2iUt36jdfXQqcBZwLnAx8O4kj1rcqapmq2qqqqY2bdrUb4UaKdPTMDsL27ZB0jzOznqRWTpRfd59dDewZWB/c9s26C7g81X1PeCOJLfRhMR1/ZSotWh62hCQVkqfI4XrgLOSnJnkNOAiYPeiPh+lGSWQZCPN6aTbe6xRksZab6FQVYeAS4BrgFuAq6rqpiRvTnJB2+0a4JtJbgY+A/xKVX2zrxoladylqoZdw0mZmpqqPXv2DLsMSVpTklxfVVOL20ftQrMkaYgMBUlSx1CQJHUMBUlSx1CQJHWW9MtrSR4N/AzwAprfHbgD+BjwMecnkqT147ihkOQjwKOBTwC/VlW3JdlKM5ndf05yWlWdu7plSpL6sJSRwsur6luDDVV1AHgH8I4jzU0kSVqbjntNYXEgJHlOkncnObtt+tlVqEuSNAQnMiHey4FfBN6Y5DHA2StakSRpaE7k7qO/rapvVdXrgecCT1vhmiRJQ3IiofCJhY2quhT4wMqVI0kapmWHQlV9bNH+O1auHEnSMC37mkKSn6NZDOeXgEPA56rqXStdmCSpfydyoflpwFOq6sUASS5f2ZIkScNyIqHwf4HNSV4J3AP84MqWJEkalhO50PzrNMtmPgZ4KPDLK1mQJGl4ljLNxTeAl1bVJwCqWarto6tclyRpCJYyUvge8K4k/3rxE0k+vPIlSZKGZSmh8DXgnwGvT/KmRc89fsUrkiQNzZKuKVTVPuAngOcmeU+ShdfVahUmSerfUkIhAFX1DeA84LHA7iQTC89JktaHpYTCFxc2qurvgH8B3A18FnjkqlQlSRqKpYTCYReYq+r+qnoVzRxIk0kcLUjSOrGUUPh0kj9McnGSRwK0p46+AnyIgZGEJGltO+7vKVTVeUm20yy/+YkkD6G5wHwN8Laq+sIq1yhJ6slS7z66uap+u6r+KfCTVfWMqnqTgaD1aG4OJidhw4bmcW5u2BVJ/Vn23EftxWZpXZqbg5kZmJ9v9vfvb/YBpqeHV5fUlxOZ+0hat3bufCAQFszPN+3SODAUpAEHDiyvXVpvDAVpwNaty2uX1pteQyHJjiS3Jtmb5NJj9Hthkkoy1Wd90q5dMDFxeNvERNMujYPeQiHJKcAVwPnAduDi9lbXxf0eAfw74PN91SYtmJ6G2VnYtg2S5nF21ovMGh99jhTOAfZW1e1VdR9wJc3vPiz2W8BbgO/0WJvUmZ6Gffvg/vubRwNB46TPUDgDuHNg/662rZPkqcCWhQV9jibJTJI9SfYcPHhw5SuVpDE1Mhea2+m4fxd43fH6VtVsVU1V1dSmTZtWvzhJGhN9hsLdwJaB/c1t24JHAE8EPptkH/B0mim6vdgsST3pMxSuA85KcmaS04CLgN0LT1bVt6tqY1VNVtUkcC1wQVXt6bFGSRprvYVCVR0CLqGZSO8W4KqquinJm5Nc0FcdkqSjW/bcRyejqq4Grl7UdtlR+p7bR02SpAeMzIVmSdLwGQqSpI6hIEnqGAqSpI6hIEnqGAqSpI6hIEnqGAqSpI6hIEnqGAqSpI6hIEnqGAqSpI6hIEnqGAqSpI6hIEnqGAqSpI6hIEnqGAqSpI6hIEnqGAqSpI6hIEnqGAqSpI6hIEnqGAqSpI6hIEnqGAqSpI6hIEnqGAqSpI6hIEnqGArSKpqbg8lJ2LCheZybG3ZF0rH1GgpJdiS5NcneJJce4fnXJrk5yY1J/jzJtj7rk1bS3BzMzMD+/VDVPM7MGAwabb2FQpJTgCuA84HtwMVJti/q9kVgqqqeDPwx8Dt91SettJ07YX7+8Lb5+aZdGlV9jhTOAfZW1e1VdR9wJXDhYIeq+kxVLXwbXQts7rE+aUUdOLC8dmkU9BkKZwB3Duzf1bYdzSuAPzvSE0lmkuxJsufgwYMrWKK0crZuXV67NApG8kJzkpcAU8Bbj/R8Vc1W1VRVTW3atKnf4qQl2rULJiYOb5uYaNqlUdVnKNwNbBnY39y2HSbJs4GdwAVV9d2eapNW3PQ0zM7Ctm2QNI+zs027NKpO7fGzrgPOSnImTRhcBPyrwQ5Jfgz4fWBHVX29x9qkVTE9bQhobeltpFBVh4BLgGuAW4CrquqmJG9OckHb7a3Aw4E/SnJDkt191SdJ6nekQFVdDVy9qO2yge1n91mPJOlwI3mhWZI0HIaCJKljKEiSOoaCJKljKEiSOoaCJKljKEiSOoaCJKljKEiSOoaCJKljKEiSOoaCJKljKEiSOoaCJKljKEiSOoaCJKljKEiSOoaCJKljKEiSOoaCJKljKEiSOoaCJKljKEiSOoaCJKljKEiSOoaCJKljKEiSOoaCJKljKEiSOoaCNKbm5mByEjZsaB7n5oZdkUbBqcMuQFL/5uZgZgbm55v9/fubfYDp6eHVpeHrdaSQZEeSW5PsTXLpEZ5/aJI/bJ//fJLJPuuTxsXOnQ8EwoL5+aZdo221R3i9hUKSU4ArgPOB7cDFSbYv6vYK4J6qehzwNuAtfdUnjZMDB5bXrtGwMMLbvx+qHhjhrWQw9DlSOAfYW1W3V9V9wJXAhYv6XAi8v93+Y+C8JOmxRmksbN26vHaNhj5GeH2GwhnAnQP7d7VtR+xTVYeAbwM/tPiNkswk2ZNkz8GDB1epXGn92rULJiYOb5uYaNo1uvoY4a3Ju4+qaraqpqpqatOmTcMuR1pzpqdhdha2bYOkeZyd9SLzqOtjhNdnKNwNbBnY39y2HbFPklOB04Fv9lKdNGamp2HfPrj//ubRQBh9fYzw+gyF64CzkpyZ5DTgImD3oj67gZe22y8C/ltVVY81StLI6mOE19vvKVTVoSSXANcApwDvraqbkrwZ2FNVu4E/AD6YZC/wNzTBIUlqTU+v7qiu119eq6qrgasXtV02sP0d4MV91iRJesCavNAsSVodhoIkqWMoSJI6hoIkqZO1fsdnkoPA/hN8+UbgGytYznrn8Voej9fyeLyW52SP17aqetBv/675UDgZSfZU1dSw61grPF7L4/FaHo/X8qzW8fL0kSSpYyhIkjrjHgqzwy5gjfF4LY/Ha3k8XsuzKsdrrK8pSJION+4jBUnSAENBktQZ21BIsiPJrUn2Jrl02PWsBUl+L8kzk5yd5NokN7Qr4J0z7NpG0cLxGth/XZJKsnGYdfUtycOS/M8kX0pyU5LfXMJrLkqyM8npST4+8NqX9VHzWjDw/fjWJH+V5MYkf5rkUSfzvmMZCklOAa4Azge2Axcn2T7cqtaEpwPXAr8D/GZVnQ1c1u7rwRaOF0m2AM8FVnDhxDXju8CzquopwNnAjiRPP85rzgc+Cfxb4Ob2tecC/7Fdj0UPfH19GnhiVT0ZuA14w8m86ViGAnAOsLeqbq+q+4ArgQuHXNNISPL2JN9vRwFfTnJfkl9J8gTgtqr6PlDAI9uXnA58dWgFD9kSjxfA24BfpTl2Y6Ua97a7D2n/PC/Jve1o/YYkf5fkTwGShCY8vkBzvB7Rtj2cZp2VQ73/JYZkKV9fVfWpdk17aEJi80l9aFWN3R+aVd3eM7D/c8A7h13XqPwB7m0fNwL72u3XAi9vt59A8xPvnTRLqG4bds0jfrwuBC5vt/cBG4dd8xCO0SnADcC9wFvats8CU+32V4DJdvupwAfa7UcAnwG+1r72p4b9dxm1r69FfT8OvORkPm9cRwpavufRDOcBfhF4TVVtAV5Ds2KeDvc84JNJJoB/T3OabWxV8xPt2TQ/xZ6T5InH6L4D+LN2+3k0YfIPaEYP70zyyCO/bKwMfj8CkGQnzShq7mTeeFxD4W5gy8D+5rZNR9D+x/aoqlo4TfRS4CPt9h/RnI5Ta9Hx+hHgTOBLSfbRfK19IcnfH2KJQ1NV36L5yX/HMbo9F/hUu/0y4CPV2AvcATx+VYsccUf4fiTJLwA/DUxXO2Q4UeMaCtcBZyU5s71odRGwe8g1jaJDwGnAT9J8Iy/4KvDP2+1nAf+r57pG1YOOV1V9uaoeW1WTVTUJ3AU8tar+enhl9ivJpoU7YpL8APAc4K8WdTsEnJbkdODUqvpm234AOK997d8D/hFwex91j6Ajfj8m2UFzveqCqpo/2Q/pdY3mUVFVh5JcAlxDc67zvVV105DLGkXfBg4CLwQ+MND+SuDyJKcC3wFmhlDbKDra8Rp3Pwy8v73rbwNwVVX9lySvH+jzFzTnw3cC/3Wg/beA9yX5MhDg16pqXKfXPtrX1zuBhwKfbq7Hc21V/ZsT/RCnudBxJfkC8E+q6nvDrmUt8HiduCTvobkJ5Nph1zKqVvvry1CQJHXG9ZqCJOkIDAVJUsdQkCR1DAVJUsdQkCR1DAVJUsdQ0FhJ8qokf93Oz/+/k/z8kOq49/i9Dut/SpLL2zUFvpzkH65WbRpvhoLGzZOAN1UzP//FwO8OuZ6legNwe1X9Y+DtwC8NuR6tU4aCxs2TgVvb7TuA+5b6wiQfTXJ9+9P6TNs2meSWJO9u2z/Vzu9Dkl9v1wv4iyQfXjStw8J7vqRdleyGJL/fTgWxuM8PAi+oqssH6n7c8v7a0tIYCho3TwJubRdtuYRmrp2lenlV/TgwBbw6yQ+17WcBV7Q/xX8LeGGSp9HMUfMUmlXEpha/WbtQyr8EntlOK/19YPoIn/tsYEsbHDcA76VZbEZacYaCxka7JOYjgKuBrwM/Abyvfe6qJKcmeVGSoy1n+OokX6JZ3WoLTRgA3FFVN7Tb1wOTwDOBj1XVd6rqb2kme1vsPODHgeva/+zPA450reBs4LKqOrsNj0/RrDGwMFeQtGLGcpZUja0nAZ+rqmcleTTNal/PAP478EHgcuD7VfXqxS9Mci7NT+zPqKr5JJ8FHtY+/d2Brt8HfmCJ9QR4f1Udb03dR9OcMqKdmfa5wK52Xv3HJdkFbK+qFyzxc6WjcqSgcfJk4IsAVXUP8CHgp9rnbqO58PyrR3nt6cA9bSA8nmbR9GP5S+BnkjwsycNpFkBZ7M+BFyV5LECSxyTZdoR+tw183muAT1TVHTTLVv5JVe0E/t9x6pGWxFDQOHkSbSi0Pg48v1285TeA1wMvPsprPwmcmuQW4D/QnEI6qqq6jmbhphtplpb8Ms18+IN9bgbeCHwqyY3Ap2nWHljsw8BTk+ylCbbXtu1PowkWaEYo0klz6myNtfan+D+guej8TeBPgBdW1f0r8d5VdW97mudzwExVfeFk33fg/d8NvAp4DHBpVT3o7iZpuQwFaZUk+RCwnebaw/ur6reHXJJ0XIaCJKnjNQVJUsdQkCR1DAVJUsdQkCR1DAVJUsdQkCR1DAVJUuf/A0PlR1okAOyKAAAAAElFTkSuQmCC\n"
     },
     "metadata": {
      "needs_background": "light"
     }
    }
   ]
  }
 ]
}
